﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Configuration;
using System.Net.Mail;
using SAS.Core;
using SAS.Core.Entity;
using SAS.Core.Result;
using SAS.DataAccess;

namespace SAS.Bussiness
{
    public class UserBO : BaseBO
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public SASResult<User> GetUserCurrentUser(User user)
        {
            return GetUser(user, user);
        }

        public SASResult<User> Login(User user, string strHash, string strSecret)
        {
            if (user == null)
            {
                user = new User();
            }

            SASResult<User> returnResult = new SASResult<User>();

            //Validate if user is already logged in
            if (String.IsNullOrEmpty(user.TokenKey))
            {
                //call to data access layer
                var userDao = new UserDAO(string.Empty);
                SASResult<string> dataAccessResult = userDao.Login(user.Email, strHash, strSecret);

                //validate result and get data
                if (dataAccessResult.IsSucessful &&
                    dataAccessResult.OutputResult != null &&
                    !string.IsNullOrEmpty(dataAccessResult.OutputResult["TokenKey"]))
                {
                    //update current token key
                    user.TokenKey = dataAccessResult.OutputResult["TokenKey"];

                    //update display name
                    user.DisplayName = dataAccessResult.OutputResult["DisplayName"];
                    user.IsActive = true; 
                    user.Hash = strHash;
                    user.Secret = strSecret;
                    returnResult.IsSucessful = true;
                    

                    //get user role name
                    const string sortCondition = "CreatedDate desc";
                    string condition = String.Format(" AND (Email = '{0}')", user.Email);
                    SASResult<IList<User>> getUserInfoResult = userDao.GetUsers(1, Int32.MaxValue, sortCondition, condition);

                    //validate
                    if(!getUserInfoResult.IsSucessful ||
                        getUserInfoResult.Result.Count == 0)
                    {
                        returnResult.IsSucessful = false;
                        returnResult.Message = "Cannot get user role";
                        returnResult.Result = null;
                    }

                    //set client role name for user
                    user.ClientRoleName = getUserInfoResult.Result[0].ClientRoleName;
                    returnResult.Result = user;
                }
                else if (!dataAccessResult.IsSucessful)
                {
                    returnResult.IsSucessful = false;
                    returnResult.Message = dataAccessResult.Message;
                    returnResult.Result = null;
                }
                else
                {
                    returnResult.IsSucessful = true;
                    returnResult.Result = user;
                }
            }

            return returnResult;
        }

        public SASResult<bool> LogOut(User user)
        {
            SASResult<bool> bussinessResult = new SASResult<bool>
                {
                    IsSucessful = false,
                    Message = String.Empty
                };

            #region Validate
            //validate current logged in user.
            if (!ValidateCurrentUser(user, bussinessResult))
            {
                return bussinessResult;
            }
            #endregion

            UserDAO userDao = new UserDAO(user.TokenKey);
            SASResult<User> dataAResult = userDao.LogOut();

            if (!dataAResult.IsSucessful)
            {
                bussinessResult.Result = false;
                bussinessResult.Message = "Can not logout system";
            }
            else
            {
                bussinessResult.IsSucessful = true;
                bussinessResult.Result = true;
                bussinessResult.Message = "Logout successfully";
            }
            return bussinessResult;
        } 

        public SASResult<IList<User>> GetUsers(User user, AdvSearch advSearch, SearchParameters searchParameters)
        {
            //create default for Business result
            SASResult<IList<User>> bussinessResult = new SASResult<IList<User>>
                                                        {
                                                            IsSucessful = false,
                                                            Message = string.Empty,
                                                            Result = new List<User>()
                                                        };
            bussinessResult.OutputResult.Add("PageNumber", "0");
            bussinessResult.OutputResult.Add("PageSize", "0");
            bussinessResult.OutputResult.Add("ResultCount", "0");

            #region Validate
            //validate current logged in user.
            if (!ValidateCurrentUser(user, bussinessResult))
            {
                return bussinessResult;
            }

            if (advSearch == null)
            {
                bussinessResult.Message = "invalid calling service";
                return bussinessResult;
            }
            #endregion
            
            //Build SQL condition string from inputted searchParameters.
            string condition = CreateCondition(searchParameters, advSearch.Paramvals);

            //Build order by condition string from order by column name and sorting expression.
            string sortCondition = String.Format("{0} {1}", advSearch.OrderBy, advSearch.Sord);

            //Call to DAL to get search result
            UserDAO userDao = new UserDAO(user.TokenKey);
            SASResult<IList<User>> dataAccessResult = userDao.GetUsers(advSearch.PageNumber, advSearch.PageSize, sortCondition, condition);

            //Validate data package
            if (dataAccessResult.IsSucessful)
            {
                bussinessResult.IsSucessful = true;
                bussinessResult.Result = dataAccessResult.Result;
                bussinessResult.OutputResult["PageNumber"] = advSearch.PageNumber.ToString(CultureInfo.InvariantCulture);
                bussinessResult.OutputResult["PageSize"] = advSearch.PageSize.ToString(CultureInfo.InvariantCulture);
                bussinessResult.OutputResult["ResultCount"] = dataAccessResult.Result.Count.ToString(CultureInfo.InvariantCulture);
            }
            else
            {
                bussinessResult.Message = dataAccessResult.Message;
            }

            return bussinessResult;
        }

        public SASResult<int> AddUser(User user, User newUser, MailSettingsSectionGroup mailSettings, string emailTemplatePath, string sasAcessURL)
        {
            //create default for Business result
            SASResult<int> bussinessResult = new SASResult<int>
            {
                IsSucessful = false,
                Message = string.Empty,
            };

            #region Validate
            //validate current logged in user.
            if (!ValidateCurrentUser(user, bussinessResult))
            {
                return bussinessResult;
            }

            if (newUser == null)
            {
                bussinessResult.Message = "Adding new user can not be performed";
                return bussinessResult;
            }

            #endregion
            
            //Active new user.
            newUser.IsActive = true;

            //Call to DAL to add new user
            UserDAO userDao = new UserDAO(user.TokenKey);
            SASResult<User> addNewUserResult = userDao.Set(newUser);

            if (!addNewUserResult.IsSucessful)
            {
                bussinessResult.Message = addNewUserResult.Message;
                return bussinessResult;
            }

            //Call to reset password to create - get default password
            SASResult<string> resetPasswordResult = userDao.ResetPassword(newUser.Email);
            if (!addNewUserResult.IsSucessful)
            {
                resetPasswordResult.Message = resetPasswordResult.Message;
                return bussinessResult;
            }

            //validate the user email to reset password
            if (addNewUserResult.IsSucessful &&
                String.CompareOrdinal(resetPasswordResult.OutputResult["IsValidEmail"], "1") != 0)
            {
                bussinessResult.Message = "the user email is invalid email";
                return bussinessResult;
            }

            //send default password to new user through email
            string newPassword = resetPasswordResult.OutputResult["NewPassword"];

            string emailContent = File.ReadAllText(emailTemplatePath);
            emailContent = emailContent.Replace("##userName##", newUser.FirstName)
                                       .Replace("##email##", newUser.Email)
                                       .Replace("##password##", newPassword)
                                       .Replace("##linkAddress##", sasAcessURL);

            string fromEmail = mailSettings.Smtp.From;
            MailMessage mailMessage = new MailMessage(fromEmail, newUser.Email)
            {
                IsBodyHtml = true,
                Body = emailContent,
                Subject = String.Format("Your eDD account has been activated."),
            };

            try
            {
                var smtp = new SmtpClient(mailSettings.Smtp.Network.Host, mailSettings.Smtp.Network.Port)
                {
                    //EnableSsl = mailSettings.Smtp.Network.EnableSsl,
                    DeliveryMethod = SmtpDeliveryMethod.Network,
                    UseDefaultCredentials = true
                    //Credentials = new NetworkCredential(mailSettings.Smtp.Network.UserName, mailSettings.Smtp.Network.Password)
                };

                //send activate mail
                smtp.Send(mailMessage);
                bussinessResult.IsSucessful = true;
            }
            catch (SmtpFailedRecipientException failedRecipientException)
            {
                Log(failedRecipientException);
                bussinessResult.IsSucessful = true;
                bussinessResult.Message = "false email address";
                return bussinessResult;
            }
            catch (SmtpException smtpException)
            {
                Log(smtpException);
                bussinessResult.IsSucessful = true;
                bussinessResult.Message = smtpException.Message + "....." + smtpException.InnerException;
                return bussinessResult;
            }


            bussinessResult.IsSucessful = true;
            bussinessResult.Result = Convert.ToInt32(addNewUserResult.OutputResult["UserId"]);

            return bussinessResult;

        }

        public SASResult<string> UpdateUser(User user, User userInfo)
        {
            //create default for Business result
            SASResult<string> bussinessResult = new SASResult<string>
            {
                IsSucessful = false,
                Message = string.Empty,
            };

            #region Validate
            //validate current logged in user.
            if (!ValidateCurrentUser(user, bussinessResult))
            {
                return bussinessResult;
            }

            if (userInfo == null)
            {
                bussinessResult.Message = "Update new user can not be performed";
                return bussinessResult;
            }

            #endregion


            SASResult<User> getUserResult = GetUser(user, userInfo);
            if(!getUserResult.IsSucessful)
            {
                bussinessResult.IsSucessful = false;
                bussinessResult.Message = getUserResult.Message;
                return bussinessResult;
            }
            if(getUserResult.Result == null)
            {
                bussinessResult.IsSucessful = true;
                bussinessResult.Message = getUserResult.Message;
                return bussinessResult;
            }
            
            User selectedUser = getUserResult.Result;

            selectedUser.Email = userInfo.Email;
            selectedUser.FirstName = userInfo.FirstName;
            selectedUser.LastName = userInfo.LastName;
            selectedUser.ClientRoleName = userInfo.ClientRoleName;
            selectedUser.Title = userInfo.Title;
            selectedUser.Phone1 = userInfo.Phone1;
            selectedUser.Phone2 = userInfo.Phone2;
            selectedUser.Address1 = userInfo.Address1;
            selectedUser.Address2 = userInfo.Address2;
            selectedUser.City = userInfo.City;
            selectedUser.PostalCode = userInfo.PostalCode;
            selectedUser.StateProv = userInfo.StateProv;
            selectedUser.Country = userInfo.Country;

            UserDAO userDAO = new UserDAO(user.TokenKey);
            selectedUser.IsActive = true;
            SASResult<User> userResult = userDAO.Set(selectedUser);

            return bussinessResult;
        } 

        /// <summary>
        /// Get all the user role name.
        /// </summary>
        /// <param name="user">Current user</param>
        /// <returns></returns>
        public SASResult<IList<string>> GetRoleNames(User user)
        {
            //create default for Business result
            SASResult<IList<string>> bussinessResult = new SASResult<IList<string>>
                                                          {
                                                              IsSucessful = false,
                                                              Message = String.Empty,
                                                              Result = new List<string>()
                                                          };

            #region Validate
            //validate current logged in user.
            if (!ValidateCurrentUser(user, bussinessResult))
            {
                return bussinessResult;
            }
            #endregion

            
            //Call to data access layer to get data
            UserDAO userDao = new UserDAO(user.TokenKey);
            SASResult<IList<string>> dataAccessResult = userDao.GetUserRoles();

            //Validate data package and get the data value
            if (dataAccessResult.IsSucessful)
            {
                bussinessResult.IsSucessful = true;
                bussinessResult.Result = dataAccessResult.Result;

                
            }
            else
            {
                bussinessResult.Message = dataAccessResult.Message;
            }

            

            return bussinessResult;
        }

        public SASResult<bool> ValidateToken(User user)
        {
            //create default for Business result
            SASResult<bool> bussinessResult = new SASResult<bool>
                                                            {
                                                                IsSucessful = false,
                                                                Message = String.Empty,
                                                                Result = false
                                                            };

            #region Validate
            //validate current logged in user.
            if (!ValidateCurrentUser(user, bussinessResult))
            {
                return bussinessResult;
            }
            #endregion


            string callFrom = String.Empty;
            UserDAO userDao = new UserDAO(user.TokenKey);

            SASResult<String> dataAccessResult = userDao.ValidateToken(callFrom);
            if (dataAccessResult.IsSucessful)
            {
                if(string.IsNullOrEmpty(dataAccessResult.OutputResult["PKUserID"]))
                {
                    bussinessResult.IsSucessful = true;
                    bussinessResult.Result = false; 
                }
                else
                {
                    bussinessResult.IsSucessful = true;
                    bussinessResult.Result = true; 
                }
            }
            else
            {
                bussinessResult.IsSucessful = false;
                bussinessResult.Result = false;    
            }

            
            return bussinessResult;
        }

        public SASResult<bool> ResetPassword(User user, string email, string origination, MailSettingsSectionGroup mailSettings, string emailTemplatePath, string sasWebUrl)
        {
            //create default for Business result
            SASResult<bool> bussinessResult = new SASResult<bool>
                                                           {
                                                               IsSucessful = false,
                                                               Message = String.Empty,
                                                               Result = false
                                                           };

            UserDAO userDAO = new UserDAO(user.TokenKey);
            SASResult<string> resetResult = userDAO.ResetPassword(email);

            if(!resetResult.IsSucessful)
            {
                bussinessResult.Message = "Currently, we cannot reset your password";
                return bussinessResult;
            }
            if(String.CompareOrdinal(resetResult.OutputResult["IsValidEmail"], "1") != 0)
            {
                bussinessResult.Message = "Wrong email address";
                return bussinessResult;
            }

            string emailContent = File.ReadAllText(emailTemplatePath);
            emailContent = emailContent.Replace("##userName##", resetResult.OutputResult["FirstName"])
                                       .Replace("##password##", resetResult.OutputResult["NewPassword"])
                                       .Replace("##linkAddress##", sasWebUrl);

            string fromEmail = mailSettings.Smtp.From;
            MailMessage mailMessage = new MailMessage(fromEmail, email)
            {
                IsBodyHtml = true,
                Body = emailContent,
                Subject = "Your eDD password has been reset.",
            };

            try
            {
                var smtp = new SmtpClient(mailSettings.Smtp.Network.Host, mailSettings.Smtp.Network.Port)
                {
                    EnableSsl = mailSettings.Smtp.Network.EnableSsl,
                    DeliveryMethod = SmtpDeliveryMethod.Network,
                    UseDefaultCredentials = mailSettings.Smtp.Network.DefaultCredentials,
                    Credentials = new NetworkCredential(mailSettings.Smtp.Network.UserName, mailSettings.Smtp.Network.Password)
                };

                //send activate mail
                smtp.Send(mailMessage);
                bussinessResult.IsSucessful = true;
                bussinessResult.Result = true;
            }
            catch (SmtpFailedRecipientException failedRecipientException)
            {
                Log(failedRecipientException);
                bussinessResult.IsSucessful = true;
                bussinessResult.Result = false;
                bussinessResult.Message = "false email address";
                return bussinessResult;
            }
            catch (SmtpException smtpException)
            {
                Log(smtpException);
                bussinessResult.IsSucessful = true;
                bussinessResult.Result = false;
                bussinessResult.Message = "Can not send email due to smtp configuration";
                return bussinessResult;
            }

            return bussinessResult;
        }

        public SASResult<bool> UpdatePassword(User user, string newPassword)
        {
            //create default for Business result
            SASResult<bool> bussinessResult = new SASResult<bool>
            {
                IsSucessful = false,
                Message = String.Empty,
                Result = false
            };

            #region Validate
            //validate current logged in user.
            if (!ValidateCurrentUser(user, bussinessResult))
            {
                return bussinessResult;
            }
            #endregion

            UserDAO userDAO = new UserDAO(user.TokenKey);
            SASResult<string> updateResult = userDAO.UpdatePassword(user.Hash, user.Secret, newPassword);

            //Validate
            if(!updateResult.IsSucessful)
            {
                bussinessResult.Message = "Currently, We cannot change password";
                return bussinessResult;
            }

            bussinessResult.IsSucessful = true;
            bussinessResult.Result = true;

            return bussinessResult;
        } 

        private SASResult<User> GetUser(User user, User userInfo)
        {
            //create default for Business result
            SASResult<User> bussinessResult = new SASResult<User>
            {
                IsSucessful = false,
                Message = string.Empty,
                Result = null
            };

            #region Validate
            //validate current logged in user.
            if (!ValidateCurrentUser(user, bussinessResult))
            {
                return bussinessResult;
            }
            #endregion

            const string sortCondition = "DisplayName desc";
            string condition = String.Format(" AND (Email = '{0}')", userInfo.Email);

            UserDAO userDAO = new UserDAO(user.TokenKey);
            SASResult<IList<User>> getUserResult = userDAO.GetUsers(1, Int32.MaxValue, sortCondition, condition);

            //validate result
            if (!getUserResult.IsSucessful)
            {
                bussinessResult.IsSucessful = false;
                bussinessResult.Message = "Cannot get current user information";
                return bussinessResult;
            }
            if (getUserResult.Result.Count == 0)
            {
                bussinessResult.IsSucessful = true;
                bussinessResult.Message = "current user is no longer available in system";
                return bussinessResult;
            }

            bussinessResult.IsSucessful = true;
            bussinessResult.Result = getUserResult.Result[0];
            return bussinessResult;
        }
    }
}